package com.xbongbong.paas.log;

import com.alibaba.fastjson.JSON;
import com.xbongbong.paas.log.entity.OperateDetailLogEntity;
import com.xbongbong.paas.log.entity.OperateLogEntity;
import com.xbongbong.paas.log.model.LoginLogModel;
import com.xbongbong.paas.log.model.OperateLogModel;
import com.xbongbong.paas.log.pojo.InfoArrPojo;
import com.xbongbong.paas.log.thread.LogThreadPoolBeanConfig;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author zcp
 * @version v1.0
 * @date 2019/7/5 16:31
 * @since v1.0
 */
@Component
public class MongoLogHelp {
    @Resource
    private OperateLogModel operateLogModel;
    @Resource
    private LoginLogModel loginLogModel;
    @Resource
    private LogThreadPoolBeanConfig logThreadPoolBeanConfig;

    private static final Logger LOGGER = LoggerFactory.getLogger(MongoLogHelp.class);

    /**
     * 生成操作日志（不需要生成详情日志，即默认detail为0）
     *
     * @param corpid            公司ID
     * @param opUserId          操作人ID
     * @param opUserName        操作人姓名
     * @param operateModuleType 操作模块枚举，用于日志记录
     * @param operateType       操作类型枚举，用于日志记录
     * @param opObjectId        所属对象ID
     * @param opObjectName      操作对象名称
     * @param memo              备注
     * @param httpHeader        目前没有优雅的方式拿到，或者说需要拿到这个值对代码有侵害，暂时用空字符串
     * @return java.lang.Integer
     * @throws XbbException
     * @author zcp
     * @date 2019/6/27 19:03
     * @version v1.0
     * @since v1.0
     */
    public Integer buildLog(String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader) throws XbbException {
        //不需要生成详情日志，detail为0。则相应的detailArr为null
        return buildLog4DetailArr(null, corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader);
    }

    /**
     * 生成操作日志（不需要生成详情日志，即默认detail为0）没有异步
     *
     * @param corpid            公司ID
     * @param opUserId          操作人ID
     * @param opUserName        操作人姓名
     * @param operateModuleType 操作模块枚举，用于日志记录
     * @param operateType       操作类型枚举，用于日志记录
     * @param opObjectId        所属对象ID
     * @param opObjectName      操作对象名称
     * @param memo              备注
     * @param httpHeader        目前没有优雅的方式拿到，或者说需要拿到这个值对代码有侵害，暂时用空字符串
     * @return java.lang.Integer
     * @throws XbbException
     * @author zcp
     * @date 2019/6/27 19:03
     * @version v1.0
     * @since v1.0
     */
    public Integer buildLogWithoutAsync(String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader) throws XbbException {
        //不需要生成详情日志，detail为0。则相应的detailArr为null
        return buildLog4DetailArrWithoutAsync(null, corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader);
    }

    /**
     * 生成操作日志，需要传detailArr（更改详情日志）
     *
     * @param detailArr         更改详情 @see DetailLogPojo
     * @param corpid            公司ID
     * @param opUserId          操作人ID
     * @param opUserName        操作人姓名
     * @param operateModuleType 操作模块枚举，用于日志记录
     * @param operateType       操作类型枚举，用于日志记录
     * @param opObjectId        所属对象ID
     * @param opObjectName      操作对象名称
     * @param memo              备注
     * @param httpHeader        目前没有优雅的方式拿到，或者说需要拿到这个值对代码有侵害，暂时用空字符串
     * @return java.lang.Integer
     * @throws XbbException
     * @author zcp
     * @date 2019/6/26 20:38
     * @version v1.0
     * @since v1.0
     */
    public Integer buildLog4DetailArr(List detailArr, String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader) throws XbbException {
        OperateLogEntity logEntity;
        //不需要处理详情
        if (detailArr == null || detailArr.size() == 0) {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ZERO);
            return operateLogModel.insert(logEntity);
        } else {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ONE);
            OperateDetailLogEntity operateDetailLogEntity = new OperateDetailLogEntity();
            operateDetailLogEntity.setDetailArr(JSON.toJSONString(detailArr));
            return operateLogModel.insertIncludeDetail(logEntity, operateDetailLogEntity);
        }
    }

    /**
     *
     * @Description: 自定义详情展示
     * @param detailArr
     * @param corpid
     * @param opUserId
     * @param opUserName
     * @param operateModuleType
     * @param operateType
     * @param opObjectId
     * @param opObjectName
     * @param memo
     * @param httpHeader
     * @param complexDetail 此参数可以用在OperateLogServiceImpl.detail方法中自定义详情页title
     * @return: java.lang.Integer
     * @Author: shen.yang
     * @Date: 2022/5/19  14:39
    */
    public Integer buildLog4DetailArrWithComplexDetail(List detailArr, String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader, Integer complexDetail) throws XbbException {
        OperateLogEntity logEntity;
        //不需要处理详情
        if (detailArr == null || detailArr.size() == 0) {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ZERO);
            return operateLogModel.insert(logEntity);
        } else {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ONE);
            OperateDetailLogEntity operateDetailLogEntity = new OperateDetailLogEntity();
            operateDetailLogEntity.setComplexDetail(complexDetail);
            operateDetailLogEntity.setDetailArr(JSON.toJSONString(detailArr));
            return operateLogModel.insertIncludeDetail(logEntity, operateDetailLogEntity);
        }
    }

    /***
     * 生成操作日志，需要传detailArr（复杂详情日志）
     *
     * @param detailArr
     * @param: corpid
     * @param: opUserId
     * @param: opUserName
     * @param: operateModuleType
     * @param: operateType
     * @param: opObjectId
     * @param: opObjectName
     * @param: memo
     * @param: httpHeader
     * @throws
     * @return java.lang.Integer
     * @author hongxiao
     * @date 2021-12-18 18:57
     * @since
     * @version
     */
    public Integer buildLog4ComplexDetailArr(List detailArr, String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader) throws XbbException {
        return buildLog4ComplexDetailArr(BasicConstant.ONE, detailArr, corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName,memo, httpHeader);
    }

    public Integer buildLog4ComplexDetailArr(Integer complexDetail,List detailArr, String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader) throws XbbException {
        OperateLogEntity logEntity;
        //不需要处理详情
        if (detailArr == null || detailArr.size() == 0) {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ZERO);
            return operateLogModel.insert(logEntity);
        } else {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ONE);
            OperateDetailLogEntity operateDetailLogEntity = new OperateDetailLogEntity();
            operateDetailLogEntity.setDetailArr(JSON.toJSONString(detailArr));
            // 复杂详情标识
            operateDetailLogEntity.setComplexDetail(complexDetail);
            return operateLogModel.insertIncludeDetail(logEntity, operateDetailLogEntity);
        }
    }

    /**
     * 生成操作日志，需要传detailArr（更改详情日志）没有异步
     *
     * @param detailArr         更改详情 @see DetailLogPojo
     * @param corpid            公司ID
     * @param opUserId          操作人ID
     * @param opUserName        操作人姓名
     * @param operateModuleType 操作模块枚举，用于日志记录
     * @param operateType       操作类型枚举，用于日志记录
     * @param opObjectId        所属对象ID
     * @param opObjectName      操作对象名称
     * @param memo              备注
     * @param httpHeader        目前没有优雅的方式拿到，或者说需要拿到这个值对代码有侵害，暂时用空字符串
     * @return java.lang.Integer
     * @throws XbbException
     * @author zcp
     * @date 2019/6/26 20:38
     * @version v1.0
     * @since v1.0
     */
    public Integer buildLog4DetailArrWithoutAsync(List detailArr, String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader) throws XbbException {
        OperateLogEntity logEntity;
        //不需要处理详情
        if (detailArr == null || detailArr.size() == 0) {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ZERO);
            return operateLogModel.insertWithoutAsync(logEntity);
        } else {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ONE);
            OperateDetailLogEntity operateDetailLogEntity = new OperateDetailLogEntity();
            operateDetailLogEntity.setDetailArr(JSON.toJSONString(detailArr));
            return operateLogModel.insertIncludeDetailWithoutAsync(logEntity, operateDetailLogEntity);
        }
    }

    /**
     * 生成操作日志
     * 注意：如果需要日志详情展示更改内容，则info不为空，且格式为JSONArray格式的字符串，key为tab、title和content
     *
     * @param infoArrPojoList   操作内容，数组型字符串：[{"tab":"", "title": "", "content": ""}]
     * @param corpid            公司ID
     * @param opUserId          操作人ID
     * @param opUserName        操作人姓名
     * @param operateModuleType 操作模块枚举，用于日志记录
     * @param operateType       操作类型枚举，用于日志记录
     * @param opObjectId        所属对象ID
     * @param opObjectName      操作对象名称
     * @param memo              备注
     * @param httpHeader        目前没有优雅的方式拿到，或者说需要拿到这个值对代码有侵害，暂时用空字符串
     * @return java.lang.Integer
     * @throws XbbException
     * @author zcp
     * @date 2019/7/8 11:15
     * @version v1.0
     * @since v1.0
     */
    public Integer buildLog4InfoArr(List<InfoArrPojo> infoArrPojoList, String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader) throws XbbException {
        OperateLogEntity logEntity;
        if (infoArrPojoList == null || infoArrPojoList.size() == 0) {
            //info为空，则不需要处理详情
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ZERO);
            return operateLogModel.insert(logEntity);
        } else {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ONE);
            OperateDetailLogEntity operateDetailLogEntity = new OperateDetailLogEntity();
            operateDetailLogEntity.setInfoArr(JSON.toJSONString(infoArrPojoList));
            return operateLogModel.insertIncludeDetail(logEntity, operateDetailLogEntity);
        }
    }

    /**
     * 生成操作日志（没有异步）
     * 注意：如果需要日志详情展示更改内容，则info不为空，且格式为JSONArray格式的字符串，key为tab、title和content
     *
     * @param infoArrPojoList   操作内容，数组型字符串：[{"tab":"", "title": "", "content": ""}]
     * @param corpid            公司ID
     * @param opUserId          操作人ID
     * @param opUserName        操作人姓名
     * @param operateModuleType 操作模块枚举，用于日志记录
     * @param operateType       操作类型枚举，用于日志记录
     * @param opObjectId        所属对象ID
     * @param opObjectName      操作对象名称
     * @param memo              备注
     * @param httpHeader        目前没有优雅的方式拿到，或者说需要拿到这个值对代码有侵害，暂时用空字符串
     * @return java.lang.Integer
     * @throws XbbException
     * @author zcp
     * @date 2019/7/8 11:15
     * @version v1.0
     * @since v1.0
     */
    public Integer buildLog4InfoArrWithoutAsync(List<InfoArrPojo> infoArrPojoList, String corpid, String opUserId, String opUserName, OperateModuleTypeEnum operateModuleType, OperateTypeEnum operateType, String opObjectId, String opObjectName, String memo, String httpHeader) throws XbbException {
        OperateLogEntity logEntity;
        if (infoArrPojoList == null || infoArrPojoList.size() == 0) {
            //info为空，则不需要处理详情
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ZERO);
            return operateLogModel.insertWithoutAsync(logEntity);
        } else {
            logEntity = new OperateLogEntity(corpid, opUserId, opUserName, operateModuleType, operateType, opObjectId, opObjectName, memo, httpHeader, BasicConstant.ONE);
            OperateDetailLogEntity operateDetailLogEntity = new OperateDetailLogEntity();
            operateDetailLogEntity.setInfoArr(JSON.toJSONString(infoArrPojoList));
            return operateLogModel.insertIncludeDetailWithoutAsync(logEntity, operateDetailLogEntity);
        }
    }

    public Integer getLoginCount(String corpid, Integer startTime, Integer endTime) {
        if(corpid == null) {
            return 0;
        }
        return loginLogModel.getUserLoginCount(corpid,startTime,endTime);
    }

    /**
     * 插入数据时保存日志
     * @param corpid
     * @param userId
     * @param userName
     * @param logName
     * @param memo
     * @param id
     * @param httpHeader
     * @param operateModuleTypeEnum
     */
    public void saveLoggerByInsert(String corpid, String userId, String userName, String logName, String memo, String id, String httpHeader,
                                   OperateModuleTypeEnum operateModuleTypeEnum, OperateTypeEnum operateTypeEnum) {
        Runnable runnable = () -> {
            try {
                buildLog(corpid, userId, userName, operateModuleTypeEnum, operateTypeEnum,
                        id, logName, memo, httpHeader);
            } catch (Exception e) {
                LOGGER.error("saveLogger fail", e);
            }
        };
        logThreadPoolBeanConfig.sysLogThreadPool().execute(runnable);
    }
}
